package com.yxsk.relay.job.admin.core.trigger;

import com.yxsk.relay.job.admin.core.collector.JobResultCollector;
import com.yxsk.relay.job.admin.core.collector.QuartzRemoteJobResultCollector;
import com.yxsk.relay.job.admin.core.executor.JobExecutor;
import com.yxsk.relay.job.admin.core.executor.listener.JobExecuteListener;
import com.yxsk.relay.job.admin.core.trigger.listener.TaskTriggerListener;
import com.yxsk.relay.job.admin.core.executor.quartz.QuartzRemoteJobExecutor;
import com.yxsk.relay.job.admin.core.executor.quartz.context.QuartzRemoteJobExecuteContext;
import com.yxsk.relay.job.admin.core.router.Router;
import com.yxsk.relay.job.admin.core.router.endpoint.EndpointRouterInfo;
import com.yxsk.relay.job.admin.core.router.selector.RouterDecisionMaker;
import com.yxsk.relay.job.admin.core.schedule.lifecycle.manage.TaskTriggerManager;
import com.yxsk.relay.job.admin.core.schedule.quartz.context.TriggerContext;
import com.yxsk.relay.job.admin.core.schedule.quartz.vo.CommonTaskTriggerResult;
import com.yxsk.relay.job.admin.core.schedule.quartz.vo.JobConfig;
import com.yxsk.relay.job.admin.core.trigger.interceptor.TaskExecuteInterceptor;
import com.yxsk.relay.job.component.common.utils.DateUtils;
import com.yxsk.relay.job.component.common.utils.SerialNoUtils;
import com.yxsk.relay.job.component.common.vo.TriggerResult;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.text.MessageFormat;
import java.util.Iterator;
import java.util.List;

/**
 * @Author 11376
 * @CreaTime 2019/6/5 14:59
 * @Description
 */
@Slf4j
@AllArgsConstructor
public class DynamicTrigger extends JobTriggerLifecycleWrapper<CommonTaskTriggerResult> {

    // 任务执行管理器
    protected TaskTriggerManager taskTriggerManager;

    // 任务触发上下文
    protected TriggerContext context;

    // 路由决策器
    protected RouterDecisionMaker routerDecisionMaker;

    @Override
    public void onStart() {
        super.onStart();
        // 任务监听
        TaskTriggerListener listener = this.taskTriggerManager.getTriggerListener();
        if (listener != null) {
            listener.beforeTrigger(this.context);
        }

    }

    @Override
    public final CommonTaskTriggerResult executeJob() {
        // 拦截
        List<TaskExecuteInterceptor> interceptors = this.taskTriggerManager.getInterceptors();
        if (!CollectionUtils.isEmpty(interceptors)) {
            Iterator<TaskExecuteInterceptor> iterator = interceptors.iterator();
            while (iterator.hasNext()) {
                TaskExecuteInterceptor interceptor = iterator.next();
                if (!interceptor.intercept(context)) {
                    return CommonTaskTriggerResult.intercepted(MessageFormat.format("任务配置: {0}\n 执行参数: {1}\n 拦截器: {2}\n", context.getJobConfig(), context.getTriggerInfo(), interceptor.getClass()));
                }
            }
        }

        // 触发任务
        try {
            return this.triggerJob();
        } catch (Exception e) {
            return CommonTaskTriggerResult.error(e);
        } finally {
            // 设置触发结束时间
            this.context.getTriggerInfo().setEndTime(DateUtils.getCurrentDate());
        }
    }

    @Override
    public void onFinish(CommonTaskTriggerResult result) {
        if (log.isDebugEnabled()) {
            if (TriggerResult.isOk(result)) {
                log.debug("触发任务成功, 结果：{}", result);
            } else {
                log.debug("触发任务失败, 结果：{}", result);
            }
        }
        super.onFinish(result);
        // 执行任务后置监听
        TaskTriggerListener listener = this.taskTriggerManager.getTriggerListener();
        if (listener != null) {
            listener.afterComplete(context, result);
        }
    }

    @Override
    public void onError(Exception e) {
        if (log.isDebugEnabled()) {
            log.debug("触发任务异常", e);
        }
        super.onError(e);
        // 执行后置监听
        TaskTriggerListener listener = this.taskTriggerManager.getTriggerListener();
        if (listener != null) {
            listener.onError(context, e);
        }
    }

    /**
     * @Author 11376
     * @Description 任务执行方法
     * @CreateTime 2019/6/6 10:04
     * @Return
     */
    protected CommonTaskTriggerResult triggerJob() throws Exception {
        JobConfig config = context.getJobConfig();
        if (log.isInfoEnabled()) {
            log.info("触发任务, 任务信息: {}, 执行参数: {}", config, context.getTriggerInfo().getTriggerParam());
        }
        // 获取执行路由
        Router router = this.routerDecisionMaker.decision(config);
        if (log.isDebugEnabled()) {
            log.debug("执行任务路由: {}", router.getClass());
        }
        // 获取执行主机
        List<EndpointRouterInfo> endpoints = router.route(context);

        if (CollectionUtils.isEmpty(endpoints)) {
            return CommonTaskTriggerResult.error("无可用执行主机");
        }

        // 获取任务执行器
        JobExecutor jobExecutor = this.getJobExecutor(this.taskTriggerManager.jobExecuteListener());

        // 执行远程任务
        executeRemoteJob(jobExecutor, endpoints);

        return CommonTaskTriggerResult.ok();
    }

    protected JobExecutor getJobExecutor(JobExecuteListener executeListener) {
        return new QuartzRemoteJobExecutor(executeListener);
    }

    /**
     * @param jobExecutor
     * @param endpoints
     * @Author 11376
     * @Description 执行远程任务
     * @CreateTime 2019/6/17 9:34
     * @Return
     */
    protected void executeRemoteJob(JobExecutor jobExecutor, List<EndpointRouterInfo> endpoints) {
        endpoints.stream().forEach(endpointInfo -> {
            // 实例化任务执行上下文
            QuartzRemoteJobExecuteContext executeContext = new QuartzRemoteJobExecuteContext();
            executeContext.setSerialNo(SerialNoUtils.nextId());
            executeContext.setJobConfig(this.context.getJobConfig());
            executeContext.setTriggerInfo(this.context.getTriggerInfo());
            executeContext.setEndpointRouterInfo(endpointInfo);

            // 执行
            jobExecutor.execute(executeContext);
        });

        // 执行任务结果处理
        // 每个触发器都应自身去触发集群任务处理
        if (this.context.getJobConfig().getExecuteModel() == JobConfig.ExecuteModel.CLUSTER && this.getClass() == DynamicTrigger.class) {
            // 任务结果处理器与执行器匹配
            JobResultCollector resultCollector = new QuartzRemoteJobResultCollector();
            resultCollector.collect(this.context.getTriggerInfo());
        }
    }

}
